﻿package  systems.particles 
{
	import bvlgari.bzero1.experience.ui.particles.motion.CatmullRom3D;
	import bvlgari.bzero1.experience.ui.particles.motion.MotionType;
	import bvlgari.bzero1.experience.ui.particles.motion.Path3D;
	import bvlgari.bzero1.experience.ui.particles.MotionManager;
	import bvlgari.bzero1.experience.ui.particles.Particle;
	import bvlgari.bzero1.experience.ui.particles.ParticleViewport;
	import bvlgari.bzero1.experience.ui.particles.Pool;
	import bvlgari.bzero1.experience.ui.particles.view.RenderMode;
	import com.bit101.components.HUISlider;
	import com.bit101.components.PushButton;
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	
	/**
	 * @author Nicolas Barradeau
	 */
	public class Attractor2 extends Sprite
	{
		

		private var tmp:BitmapData;
		private var bd:BitmapData;
		private var p:Number;
		private var scale:Number = 100;
		
		private var aSlider:HUISlider 
		private var bSlider:HUISlider 
		private var cSlider:HUISlider 
		private var dSlider:HUISlider 
		private var go:PushButton;
		private var random:PushButton;
		
		public var minX:Number;
		public var minY:Number;
		public var minZ:Number;
		public var maxX:Number;
		public var maxY:Number;
		public var maxZ:Number;
		 
		private var center:PushButton
		
		private var _x:Number, _y:Number;
		private var _a:Number, _b:Number, _c:Number, _d:Number;
		private var a:Number, b:Number, c:Number, d:Number;

		private var points:Vector.<Particle>;
		private var pool:Pool;
		private var view:ParticleViewport;
		private var waypoints:Vector.<Particle>;
		
		public function Attractor2():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		private function init(e:Event = null):void 
		{
			
			pool = new Pool();
			pool.createBunch( 2500 );
			
			view = new ParticleViewport( 800, 600, 0 );
			addChild( view );
			
			
			removeEventListener(Event.ADDED_TO_STAGE, init);
			tmp = new BitmapData( 500, 500, true ,0x00000000)
			bd = new BitmapData( 500, 500, true ,0x00000000 )
			addChild( new Bitmap( bd ));
			
			aSlider = new HUISlider( this, 10, 10, 'A', reset );
			bSlider = new HUISlider( this, 10, 30, 'B', reset );
			cSlider = new HUISlider( this, 10, 50, 'C', reset );
			dSlider = new HUISlider( this, 10, 70, 'D', reset );
			
			aSlider.minimum = bSlider.minimum = cSlider.minimum = dSlider.minimum = 0;
			aSlider.maximum = bSlider.maximum = cSlider.maximum = dSlider.maximum = Math.PI * 2 * 100 ;
			aSlider.width = bSlider.width = cSlider.width = dSlider.width = 480;
			
			go = new PushButton( this, 10, 90, 'go', goHandler )
			random = new PushButton( this, 150, 90, 'random', randomHandler )
			
			addEventListener( Event.ENTER_FRAME, oef );
			
			
			
		}
		
		private function goHandler(e:Event):void 
		{
			graphics.clear();
			pool.path3d = new Path3D( waypoints,50, true );
			MotionManager.assign( pool, MotionType.PATH_3D );
		}
		
		private function randomHandler(e:Event):void 
		{
			
			a = Math.random() * Math.PI * 2
			b = Math.random() * Math.PI * 2
			c = Math.random() * Math.PI * 2
			d = Math.random() * Math.PI * 2
			update( e );
			graphics.clear();
			pool.path3d = new Path3D( waypoints,50, true );
			MotionManager.assign( pool, MotionType.PATH_3D );
			
		}
		private function oef(e:Event):void 
		{
			pool.update();
			view.render( RenderMode.LINES, pool );
			
		}
		
		private function reset( e:Event ):void
		{
			a = aSlider.value * .01
			b = bSlider.value * .01
			c = cSlider.value * .01
			d = dSlider.value * .01 
			update( e );
			render();
			pool.path3d = new Path3D( waypoints,50, true );
			
		}
		
		private function update( e:Event ):void
		{
			
			
			bd.fillRect( bd.rect, 0x0 );
			
			var _x:Number, _y:Number, _z:Number, lx:Number, ly:Number, lz:Number, size:Number = 200;
			
			_x = _y = _z = Number.MIN_VALUE;
			lx = ly = lz = 0;
			
			var total:int = 1000000;
			var i:int = total;
			
			waypoints = new Vector.<Particle>();
			while ( i-=2000 )
			{
				
				_x = Math.sin( a * ly ) - lz * Math.cos( b * lx )
				_y = lz * Math.sin( c * lx ) - Math.cos( d * ly )
				_z = Math.sin( lx );
				
				lx = _x;
				ly = _y;
				lz = _z;
				
				waypoints.push( new Particle( 400 + _x * size, 300 + _y * size, 250 + _z * size ) );
				
			}
			
			boundingBox();
			
			
			
		}
		
		private function render():void
		{
		
			graphics.clear();
			
			var minZ:Number = Number.MAX_VALUE;
			var maxZ:Number = Number.MIN_VALUE;
			var p:Particle
			for each( p in waypoints )
			{
				if ( p.z < minZ ) minZ = p.z;
				if ( p.z > maxZ ) maxZ = p.z;
			}
			waypoints.sort( zsort );
			maxZ -= minZ;
			
			for each ( p in waypoints )
			{
				graphics.beginFill( 0x0000CC );
				graphics.drawCircle( p.x, p.y, 1 + 5 * ( p.z - minZ ) / maxZ );
				graphics.endFill();
			}
			
		}
		public function boundingBox():void
		{
			
			minX = minY = minZ = Number.MAX_VALUE;
			maxX = maxY = maxZ = Number.MIN_VALUE;
			
			var midx:Number
			var midy:Number
			var midz:Number
			
			var sx:Number
			var sy:Number
			var sz:Number
			
			var p:Particle;
			var i:int;
			
			for ( i = 0; i < waypoints.length; i++ )
			{
				p = waypoints[ i ];
				
				if ( p.x < minX ) minX = p.x;
				if ( p.y < minY ) minY = p.y;
				if ( p.z < minZ ) minZ = p.z;
				
				if ( p.x > maxX ) maxX = p.x;
				if ( p.y > maxY ) maxY = p.y;
				if ( p.z > maxZ ) maxZ = p.z;
				
			}
			midx = maxX - minX
			midy = maxY - minY
			//midx = maxX - minX
			for ( i = 0; i < waypoints.length; i++ )
			{
				
				p = waypoints[ i ];
				/*
				p.x = map( p.x, minX, maxX, 250, 750 );  
				p.y = map( p.y, minY, maxY, 100, 500 );  
				p.z = map( p.z, minZ, maxZ, 0, 500 );
				*/
				p.x = 250 - midx / 2 + p.x - minX; 
				p.y = 250 - midy / 2 + p.y - minY; 
				p.z = map( p.z, minZ, maxZ, 0, 500 );
			}
			
			render();
			
		}
		private function zsort( a:Particle, b:Particle ):Number 
		{ 
			return (a.z < b.z) ? 1 : -1;
		}
		
		private function normalize(value:Number, minimum:Number, maximum:Number):Number 
		{
			return (value - minimum) / (maximum - minimum);
		}
		private function interpolate( t:Number, minimum:Number, maximum:Number):Number 
		{
			return minimum + (maximum - minimum) * t;
		}
		private function map( value:Number, min1:Number, max1:Number, min2:Number, max2:Number):Number 
		{
			return interpolate( normalize(value, min1, max1), min2, max2);
		}
	}
}
class Particle
{
	
	public var a:int = 0;
	public var s:Number = 0;
	
	
	public var x:int;
	public var ox:int;
	public var y:int;
	public var oy:int;
	
	public var color:uint = 0xFF777777;
	
	public function Particle ( x:int, y:int, color:uint = 0xFFFFFFFF )
	{
		this.x = ox = x;
		this.y = oy = y;
		this.color = color;
	}
}
